NetBSD de Blinkt
https://gyazo.com/61769b356687931398e516095d9e8a33
2018年8月4日(土) OSC 2018 Kyoto
関西*BSDユーザ会研究会番外編
むとうたけし@関西*BSDユーザ会 (@610t) Blinkt!ってなあに?
Raspberry Pi 40ピンヘッダ用の安価な8連フルカラーLED
GPIOの23(DATA)と24(CLOCK)を使う (ピン配置) 1LEDあたりr,g,b x 8bit, brightness x 5 bit で、シリアルに書き込んでいく
DATAにセットしたデータをCLOCKの立ち下がりで書き込む
https://gyazo.com/c2d0b9273f0977a33beba637edcd7370
Raspbian用Blinkt!ライブラリの構成
table: Blinkt!ライブラリ階層
記述言語
アプリケーション python
blinkt.py pythonモジュール
RPi.GPIO C言語で記述されたpythonモジュール
OS GPIO layer C言語
NetBSDのGPIO
NetBSDのGPIO関連
デバイスファイル: /dev/gpio0
ポートモード設定ファイル: gpio.conf(5)
プログラムインタフェース: gpio(4)
ユーザランド操作コマンド: gpioctl(8)
NetBSD GPIOのポート初期設定
OS初期化時に /etc/gpio.confの情報に基づいて行う
/etc/rc.confにgpio=YESが必要
securelevelの関係で、ブート終了後はGPIOのポート設定変更はできない
INSECUREオプション設定をしたkernelは例外
code: /etc/gpio.confの例
gpio0 23 set out dat
gpio0 24 set out clk
gpio0 25 set in sw
ユーザランド操作コマンド: gpioctl (8)
GPIO出力
code: shell
$ sudo gpioctl gpio0 23 1
pin 23: state 0 -> 1
GPIO入力
code: shell
$ sudo gpioctl -s gpio0 sw
1
プログラムインタフェース: gpio (4)
初期化: デバイスをopen
fd=open("/dev/gpio0",O_RDWR))
GPIO出力
code: gpio_out.c
struct gpio_req req;
memset(&req, 0, sizeof(req));
req.gp_pin = pin;
req.gp_value = v;
ioctl(fd, GPIOWRITE, &req);
GPIO入力
code: gpio_input.c
ioctl(fd, GPIOREAD, &req);
NetBSDでBlinkt!を使うために
方針: 極力、楽にやる
ライブラリは全部を実装するのではなく、使うものだけ
Blinkt!アプリケーション(python)は、変更なしでそのまま使いたい
結論: RPi.GPIOライブラリで必要なところだけを作る
実装したもの: output, setmode, setwarnings, setup
Python版 RPi.GPIOライブラリ
Pythonライブラリ内で、gpioctl(8)をsubprocessから叩いて動かす
とてもコードが短い
遅いorz
code: GPIO.py
import subprocess
BCM=0
OUT=0
IN=1
def output(pin,v):
if v>0: v=1
shell="gpioctl -q gpio0 %d %d" % (pin,v)
subprocess.call(shell.split())
# dummy functions
def setmode(mode):
print "setmode:",mode
def setwarnings(f):
print "setwarnings:",f
def setup(pin,mode):
print "setup:",pin, mode
C版 RPi.GPIOライブラリ
Pythonモジュールとして作るのがめんどくさかった
code: GPIO.c
static PyObject *bcm;
static PyObject *out;
static PyObject *in;
int fd;
// 初期化
PyObject* GPIO_setup(PyObject* self, PyObject* args)
{
int pin,mode;
if (!PyArg_ParseTuple(args, "ii", &pin, &mode))
return NULL;
printf("setup: %d %d\n",pin,mode);
if((fd=open("/dev/gpio0",O_RDWR)) == -1)
err(EXIT_FAILURE, "%s", DEV);
return Py_BuildValue("");
}
// GPIO出力
PyObject* GPIO_output(PyObject* self, PyObject* args)
{
int pin,v;
struct gpio_req req;
if (!PyArg_ParseTuple(args, "ii", &pin, &v))
return NULL;
printf("output: %d %d\n",pin,v);
if(v>1) v=1;
if(v<0) v=0;
memset(&req, 0, sizeof(req));
req.gp_pin = pin;
req.gp_value = v;
if(ioctl(fd, GPIOWRITE, &req)==-1)
err(EXIT_FAILURE, "GPIOWRITE");
return Py_BuildValue("");
}
// setmode, setwarningは何もしない
PyObject* GPIO_setmode(PyObject* self, PyObject* args)
{
int mode;
if (!PyArg_ParseTuple(args, "i", &mode))
return NULL;
printf("setmode: %d\n",mode);
return Py_BuildValue("");
}
PyObject* GPIO_setwarnings(PyObject* self, PyObject* args)
{
int f;
if (!PyArg_ParseTuple(args, "i", &f))
return NULL;
printf("setwarnings: %d\n",f);
return Py_BuildValue("");
}
static PyMethodDef GPIOmethods[] = {
{"output", GPIO_output, METH_VARARGS},
{"setmode", GPIO_setmode, METH_VARARGS},
{"setwarnings", GPIO_setwarnings, METH_VARARGS},
{"setup", GPIO_setup, METH_VARARGS},
{NULL},
};
void initGPIO()
{
PyObject *module = NULL;
module=Py_InitModule("GPIO", GPIOmethods);
bcm = Py_BuildValue("i", BCM);
PyModule_AddObject(module, "BCM", bcm);
out = Py_BuildValue("i", OUT);
PyModule_AddObject(module, "OUT", out);
in = Py_BuildValue("i", IN);
PyModule_AddObject(module, "IN", in);
}
ハマりどころ
なぜか、0か1かのはずのoutputに、128とか飛んでくる
1より大きい値は1として動かしたら、それらしく動く
なぜか、gccでshard libraryを作ると、動かないorz
code:shell
rpi$ cc -shared GPIO.c -o GPIO.so -I/usr/pkg/include/python2.7
rpi$ sudo python2.7 rainbow.py
/home/mutoh/py/RPi/GPIO.so: text relocations
Traceback (most recent call last):
File "rainbow.py", line 6, in <module>
import blinkt
File "/home/mutoh/py/blinkt.py", line 4, in <module>
import RPi.GPIO as GPIO
ImportError: /home/mutoh/py/RPi/GPIO.so: Cannot write-enable text segment: Permission denied
-fPICを忘れてたorz
cc -shared -fPIC GPIO.c -o GPIO.so -I/usr/pkg/include/python2.7
おわりに
NetBSD/evbarm, aarch64 at Raspberry Piで、Blinkt!を使えました。
ほとんどコードは書いてません。
みなさんもピカピカしてみませんか?